﻿using Microsoft.Extensions.DependencyInjection;
using Modules.Constructor.Repositories;
using PmSoft;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace Modules.Constructor;

/// <summary>
/// 建设单位信用代码主键索引器
/// </summary>
[UseDI(ServiceLifetime.Scoped)]
public class ConstructorCodeIndexer
{
    private static readonly ConcurrentDictionary<int, string> idToKeyDict = new();
    private static readonly ConcurrentDictionary<string, int> keyToIdDict = new();
    private static readonly SemaphoreSlim _lock = new(initialCount: 1, maxCount: 1);

    private readonly ConstructorRepository constructorRepository;

    public ConstructorCodeIndexer(ConstructorRepository constructorRepository)
    {
        this.constructorRepository = constructorRepository;
    }

    /// <summary>
    /// 根据企业ID获取企业信用代码
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public string GetConstructorCode(int id)
    {
        if (idToKeyDict.TryGetValue(id, out string? corpCode))
            return corpCode;

        try
        {
            _lock.Wait();

            if (idToKeyDict.TryGetValue(id, out corpCode))
                return corpCode;

            var constructorInfo = constructorRepository.Get(id);
            if (constructorInfo != null
                && !string.IsNullOrEmpty(constructorInfo.Code)
                && idToKeyDict.TryAdd(id, constructorInfo.Code))
            {
                return constructorInfo.Code;
            }
            return string.Empty;
        }
        finally
        {
            _lock.Release();
        }
    }

    /// <summary>
    /// 根据企业信用代码获取企业ID
    /// </summary>
    /// <param name="constructorCode"></param>
    /// <returns></returns>
    public int? GetId(string constructorCode)
    {
        if (keyToIdDict.TryGetValue(constructorCode, out int id))
            return id;
        try
        {
            _lock.Wait();

            if (keyToIdDict.TryGetValue(constructorCode, out id))
                return id;

            int? constructorId = constructorRepository.GetConstructorId(constructorCode);
            if (constructorId.HasValue && constructorId > 0 && keyToIdDict.TryAdd(constructorCode, constructorId.Value))
                return constructorId.Value;

            return null;
        }
        finally
        {
            _lock.Release();
        }
    }

    public bool Remove(int id)
    {
        if (idToKeyDict.TryRemove(id, out string? key)
            && keyToIdDict.TryRemove(key, out _))
            return true;
        return false;
    }

}
